using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Collections.Specialized;
using System.Xml;
using System.Net;

namespace CodePlex.Resourceful.Wadl
{
    public class ApplicationDescriptionService : IService
    {
        private readonly ApplicationDescription _app;
        private readonly string _wadl;

        public ApplicationDescriptionService(ApplicationDescription app, string wadl)
        {
            _app = app;
            _wadl = wadl;
        }

        public void Process(IHttpContext context)
        {
            if (!context.Request.IsRelative)
            {
                return;
            }

            if (context.Request.RelativeUri == _wadl)
            {
                this.ProcessWadl(context);
            }

            InternalContext c = this.NewContext(context) as InternalContext;

            LocalApplicationMethod localMethod = c.ApplicationMethod as LocalApplicationMethod;
            if (localMethod != null)
            {
                localMethod.Handler(c);
            }

        }

        public IRepresentationContext NewContext(IHttpContext context)
        {
            NameValuePairs templateParameters = new NameValuePairs();


            ApplicationResource resource = _app.FindResource(context.Request.RelativeUri, templateParameters);

            ApplicationMethod method = null;

            if (resource != null)
            {
                method = _app.FindMethod(resource, context.Request.HttpMethod);
            }

            return new InternalContext(context, method, templateParameters);

        }

        private void ProcessWadl(IHttpContext context)
        {

            string responseString = Utils.ToString(delegate(XmlTextWriter writer)
            {
                ApplicationDescription.ToXml(context.RootUri, _app, writer);
            });

            //  context.Response.ContentType = MediaTypes.ApplicationVndSunWadlXml;
            //   context.Response.ContentType = MediaTypes.ApplicationXml;
            context.Response.ContentType = MediaType.TextPlain;

            Utils.PostProcess(responseString, context, DateTime.Now);

        }









        private class InternalContext : IRepresentationContext
        {
            private readonly IHttpContext _context;
            private readonly ApplicationMethod _method;

            private readonly NameValuePairs _templateParameters;

            private readonly MemoryStream _stream;

            public InternalContext(IHttpContext context, ApplicationMethod method, NameValuePairs templateParameters)
            {
                _context = context;
                _method = method;
                _templateParameters = templateParameters;

                _stream = new MemoryStream();
            }


            public ApplicationMethod ApplicationMethod
            {
                get
                {
                    return _method;
                }
            }



            public byte[] ResponseBytes
            {
                get
                {
                    return _stream.ToArray();
                }
            }
            public DateTime LastModified
            {
                get
                {
                    return DateTime.Now;
                }
            }

            public NameValuePairs TemplateParameters
            {
                get { return _templateParameters; }
            }

            public IRepresentationRequest Request
            {
                get { return new InternalRequest(_context); }
            }

            public IRepresentationResponse Response
            {
                get { return new InternalResponse(this,_context, Fn.ToFn(_stream)); }
            }



            private class InternalResponse : IRepresentationResponse
            {
                private readonly InternalContext _parent;
                private readonly Func20<MemoryStream> _stream;
                private readonly IHttpContext _context;

                public InternalResponse(InternalContext parent, IHttpContext context, Func20<MemoryStream> stream)
                {
                    _parent = parent;
                    _context = context;
                    _stream = stream;
                }


                public string MediaType
                {
                    get
                    {
                        return _context.Response.ContentType;
                    }
                    set
                    {
                        _context.Response.ContentType = value;
                    }
                }

                public TextWriter GetTextWriter()
                {
                    return new StreamWriter(_stream(), Encoding.UTF8);
                }


               


                public void SetStatus(HttpStatus status)
                {
                    _context.Response.StatusCode = status.Code;
                    _context.Response.StatusDescription = status.Description;
          
                  
                }




                public string Location
                {
                    set
                    {
                        _context.Response.SetHeader(HttpHeader.Location, value);
                    }
                }



               
                public void Render(HttpStatus status)
                {
                    this.Render(status, null,(Stream) null);
                }

                public void Render(HttpStatus status, string mediaType, string representation)
                {

                    this.Render(status, mediaType, Utils.ToStream(representation));

                }

                public void Render(HttpStatus status, string mediaType, Stream representation)
                {
                    this.SetStatus(status);

                    if (mediaType != null && representation != null)
                    {
                        this.MediaType = mediaType;

                        Utils.BufferedTransfer(representation, _stream());
                    }



                    Utils.PostProcess(_parent.ResponseBytes, _context, _parent.LastModified);
                }


               

                public bool IsRendered
                {
                    get { return _context.Response.IsEnded; }
                }




                public void SetHeader(string name, string value)
                {
                    _context.Response.SetHeader(name, value);
                }


               

               
                
            }
            private class InternalRequest : IRepresentationRequest
            {
                private readonly IHttpContext _context;
                public InternalRequest(IHttpContext context)
                {
                    _context = context;
                }
                public bool Accepts(string mediaType)
                {
                    return _context.Request.AcceptTypes.Contains(mediaType);
                }



               

                public string MediaType
                {
                    get { return _context.Request.ContentType; }
                }




                public Stream GetEntityStream()
                {
                    return _context.Request.GetRequestStream();
                }



               

                public DateTime? IfModifiedSince
                {
                    get 
                    {

                        try
                        {
                            return Utils.FromHttpDate(_context.Request.Headers[HttpHeader.IfModifiedSince]);
                        }
                        catch
                        {
                            return null;
                        }
                    
                    
                    }
                }

                
            }


         

            public Uri RootUri
            {
                get { return _context.RootUri; }
            }





            public string BasicAuthUsername
            {
                get { return _context.BasicAuthUsername; }
            }

            public string BasicAuthPassword
            {
                get { return _context.BasicAuthPassword; }
            }

           
        }


   
      

    }


}
